package com.qs.javame.thread.think;

import java.util.concurrent.TimeUnit;

/**
 * 验证等待/通知的经典范式，进而实现生产者消费者的小例子
 */
public class TestDemo2 {

    public static void main(String[] args) {
        Task task = new Task();
        Thread consume = new Thread(task::consume, "consume");
        consume.start();

        Thread produce = new Thread(task::product, "produce");
        produce.start();
    }
}

/**
 * 满足等待/通知的经典范式
 */
class Task {
    private int i = 0;

    public synchronized void consume() {
        //不满足条件，等待
        while (i <= 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //满足条件，处理逻辑
        i--;
        System.out.println(Thread.currentThread().getName() + "--消费后i=" + i);

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void product() {
        //更改条件
        i++;
        System.out.println(Thread.currentThread().getName() + "-生产i=" + i);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //唤醒操作
        this.notifyAll();
    }
}


/**
 * 由等待/通知机制实现的生产者消费者
 */
class FullTask {

    private int i = 0;
    private final int max = 20;

    public static void main(String[] args) {
        FullTask task = new FullTask();

        Thread consume = new Thread(task::consume);
        consume.start();

        Thread produce = new Thread(task::product);
        produce.start();
    }


    public void consume() {
        //注意for死循环的位置，需要在同步块之外，因为一个线程被唤醒后，只有竞争到锁该线程才有机会执行，如果进行唤醒操作后，不释放锁，那么唤醒的意义在哪？
        // 试想下：如果这里使用同步方法，结果会是什么样子？
        for (; ; ) {
            synchronized (this) {
                //不满足条件，等待
                while (i <= 0) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //改变条件
                i--;
                System.out.println(Thread.currentThread().getName() + "--消费后i=" + i);

                //唤醒
                this.notifyAll();
            }
        }
    }


    public void product() {
        for (; ; ) {
            synchronized (this) {
                //不满足条件，等待
                while (i >= max) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //改变条件
                i++;
                System.out.println(Thread.currentThread().getName() + "-生产i=" + i);

                //唤醒
                this.notifyAll();
            }
        }
    }

}